/* 
 *  Copyright (C) 2006 James Young
 * `gurumind(a)gmail.com
 * 
 */

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace IPDEditor
{
    enum MbMode { Plain, ReducedKeyboard };
    public partial class IPDEditorAutoText : IPDEditor.IPDEditorBase
    {
        //AutoText
        protected const byte fldtypeAutoTextInput = 1;
        protected const byte fldtypeAutoTextInputNonEng = 129;
        protected const byte fldtypeAutoTextOutput = 2;
        protected const byte fldtypeAutoTextOutputNonEng = 130;
        // field 4,5: special case: 0xFFFFFFFF, 0x00000001, smart case: 0x00000000, 00000000
        protected const byte fldtypeAutoTextCase1 = 4;
        protected const byte fldtypeAutoTextCase2 = 5;
        protected const byte fldtypeAutoTextLanguage = 6;

        protected const int langAll = 0; 
        protected const int langChinese = 0x7A680000;
        protected const int langEnglish = 0x656E0000;
        protected const int langEnglishGB = 0x656E4742;
        protected const int langEnglishUS = 0x656E5553;
        protected const int langDE = 0x64650000;
        protected const int langEL = 0x656C0000;
        protected const int langES = 0x65730000;
        protected const int langFR = 0x66720000;
        protected const int langIT = 0x69740000;
        protected const int langPT = 0x70740000;

        protected Dictionary<int, string> arrLang;

        protected const int caseSmart = 0;
        protected const int caseSpecial = -1;
        protected const int caseSpecial2 = 1;

        string defSrc;
        string defDst;
        int defCase;
        int defLang;

        short defDbId;
        byte defDbVer;

        bool isNew;

        public IPDEditorAutoText()
        {
            InitializeComponent();
            
            arrLang = new Dictionary<int,string>();
            arrLang.Add(langAll, "All Language");
            arrLang.Add(langChinese, "Chinese");
            arrLang.Add(langEnglish, "English");
            arrLang.Add(langEnglishGB, "English GB");
            arrLang.Add(langEnglishUS, "English US");
            arrLang.Add(langDE, "DE");
            arrLang.Add(langEL, "EL");
            arrLang.Add(langES, "ES");
            arrLang.Add(langFR, "France");
            arrLang.Add(langIT, "Itily");
            arrLang.Add(langPT, "PT");

            foreach(KeyValuePair<int, string> d in arrLang)
            {
                cbLang.Items.Add(d.Value);
            }
        }

        private void IPDEditorAutoText_Load(object sender, EventArgs e)
        {
            tbeLabel.Text = "Auto Text Visual Editor";
        }

        public override void FillData(IPDDatabase record)
        {
            string src = defSrc;
            string dst = defDst;
            int lang = defLang;
            int csc = defCase;

            foreach (IPDField fld in record.Items)
            {
                if (fld.type == fldtypeAutoTextInput || fld.type == fldtypeAutoTextInputNonEng)
                    src = EncUtil.AutoBin2String(fld.data);
                else if (fld.type == fldtypeAutoTextOutput || fld.type == fldtypeAutoTextOutputNonEng)
                    dst = EncUtil.AutoBin2String(fld.data);
                else if (fld.type == fldtypeAutoTextLanguage)
                {
                    lang = EncUtil.BIN2Int(fld.data);
                }
                else if (fld.type == fldtypeAutoTextCase1)
                {
                    csc = EncUtil.BIN2Int(fld.data);
                }
            }

            SetValue(src, dst, lang, csc);
            isNew = false;
        }

        private void SetValue(string src, string dst, int lang, int cse)
        {
            tbDestination.Text = dst;
            tbSource.Text = src;

            for (int i = 0; i < arrLang.Count; i++)
            {
                if(arrLang[lang] == cbLang.Items[i].ToString())
                {
                    cbLang.SelectedIndex = i;
                    break;
                }
            }

            if (cse == caseSmart)
                rbSmartCase.Checked = true;
            else
                rbSpecialCase.Checked = true;
        }

        protected override void SetDefault()
        {
            defSrc = tbSource.Text;
            defDst = tbDestination.Text;

            if (rbSmartCase.Checked)
                defCase = caseSmart;
            else
                defCase = caseSpecial;

            foreach (KeyValuePair<int, string> d in arrLang)
            {
                if (d.Value == cbLang.SelectedText)
                {
                    defLang = d.Key;
                    break;
                }
            }
        }

        protected override void CreateNew()
        {
            //clone some under layer variables
            defDbId = _vr.record.dbId;
            defDbVer = _vr.record.dbver;
  
            SetValue(defSrc, defDst, defLang, defCase);
            isNew = true;
        }

        protected override void Delete()
        {
            _vr.RemoveBrother(_vr.record);
        }

        protected override void Import()
        {
#if !DEBUG
            MessageBox.Show("The import process will take minutes. Please be patient.");
#endif
            if (DialogResult.OK == ofd.ShowDialog(this))
            {                
                Stream s = File.OpenRead(ofd.FileName);
                StreamReader sr = new StreamReader(s, Encoding.UTF8);
                
                char [] sep1 = {'='};
                char [] sep2 = {'|'};
                char[] sepSpc = { '\n', '\r', ' ' };
                string line = sr.ReadLine();
                if (line != null)
                {
                    line = line.Trim();
                    line = EncUtil.UnEscape(line);
                }

                MbMode mbMode = MbMode.Plain;
                if (line.IndexOf("|") < 0)
                    mbMode = MbMode.ReducedKeyboard;

                int errLine = 0;
                StringBuilder sb = new StringBuilder();

                mainForm mf = (mainForm)this.TopLevelControl;
                //mf.tv.SuspendLayout();
                mf.Cursor = Cursors.WaitCursor;
                int n = 0;
                do
                {
                    string[] ss1 = line.Split(sep1);
                    if (ss1.Length == 2)
                    {
                        if (mbMode == MbMode.Plain)
                        {
                            string[] ss2 = ss1[1].Split(sep2);
                            if (ss2.Length == 1)
                            {
                                CreateSave(ss1[0], ss1[1]);
                            }
                            else
                            {

                                sb.Remove(0, sb.Length);

                                if (ss2.Length <= 9)
                                {
                                    for (int i = 0; i < ss2.Length; i++)
                                        sb.AppendFormat("{0}{1}", i + 1, ss2[i]);
                                }
                                else
                                {
                                    int len = ss2.Length > 36 ? 36 : ss2.Length;
                                    for (int i = 0; i < 9; i++)
                                        sb.AppendFormat("{0}{1}", i + 1, ss2[i]);
                                    for (int i = 10; i < len; i++)
                                    {
                                        sb.Append((char)(((byte)'a') + i - 10));
                                        sb.Append(ss2[i]);
                                    }
                                }
                                CreateSave(ss1[0] + "0", sb.ToString());

                                //selective char                            
                                int len1 = ss2.Length > 9 ? 9 : ss2.Length;
                                int len2 = ss2.Length > 36 ? 36 : ss2.Length;
                                for (int i = 0; i < len1; i++)
                                    CreateSave(ss1[0] + (i + 1).ToString(), ss2[i]);
                                for (int i = 10; i < len2 && i > len1; i++)
                                {
                                    string typer = ((char)(((byte)'a') + i - 10)).ToString();
                                    CreateSave(ss1[0] + typer, ss2[i]);
                                }
                            }
                        }
                        else
                        {
                            CreateSave(ss1[0], ss1[1]);
                        }
                    }
                    else
                        errLine++;
                    line = sr.ReadLine();
                    if (line != null)
                    {
                        line = line.Trim();
                        line = EncUtil.UnEscape(line);
                    }
                    n++;
#if DEBUG
                    if (n > 50)
                        break;
#endif
                } while (line != null);
                mf.Cursor = Cursors.Arrow;
                //mf.tv.ResumeLayout();

                sr.Close();
                s.Close();

                MessageBox.Show(string.Format("Total {0} items have been imported. {1} mis-format line bypassed.", n, errLine));
            }
        }

        private void CreateSave(string input, string output)
        {
            IPDDatabase record = Save(input, output);
            _vr.AppendBrother(record);
        }

        private IPDDatabase Save(string input, string output)
        {
            string src = defSrc + input;
            string dst = defDst + output;
            IPDDatabase record = CreateNew(src, dst);
            if (Save(record, src, dst, defCase, defLang))
                return record;
            else
                return null;
        }

        private bool Save(IPDDatabase record, string input, string output, int replCase, int language)
        {
            foreach (IPDField fld in record.Items)
            {
                if (fld.type == fldtypeAutoTextInput)
                    _vr.UpdateFieldAsMixString(fld, input, Encoding.ASCII);
                else if(fld.type == fldtypeAutoTextInputNonEng)
                    _vr.UpdateFieldAsMixString(fld, input, Encoding.UTF8);
                else if (fld.type == fldtypeAutoTextOutput)
                    _vr.UpdateFieldAsMixString(fld, output, Encoding.ASCII);
                else if(fld.type == fldtypeAutoTextOutputNonEng)
                    _vr.UpdateFieldAsMixString(fld, output, Encoding.UTF8);

                else if (fld.type == fldtypeAutoTextLanguage)
                {
                    _vr.UpdateFieldAsNumber(fld, language);
                }
                else if (fld.type == fldtypeAutoTextCase1)
                {
                    if (replCase == caseSmart)
                        _vr.UpdateFieldAsNumber(fld, caseSmart);
                    else
                        _vr.UpdateFieldAsNumber(fld, caseSpecial);
                }
                else if (fld.type == fldtypeAutoTextCase2)
                {
                    if (replCase == caseSmart)
                        _vr.UpdateFieldAsNumber(fld, caseSmart);
                    else
                        _vr.UpdateFieldAsNumber(fld, caseSpecial2);
                }
            }
            return true;
        }

        protected override void Save()
        {
            IPDDatabase record;
            if (isNew)
            {
                record = CreateNew(tbSource.Text, tbDestination.Text);
            }
            else
            {
                record = _vr.record;
            }

            int lang = langAll;
            foreach (KeyValuePair<int, string> d in arrLang)
            {
                if (d.Value == cbLang.SelectedText)
                {
                    lang = d.Key;
                    break;
                }
            }

            Save(record, tbSource.Text, tbDestination.Text, rbSmartCase.Checked ? caseSmart : caseSpecial, lang);

            if (isNew)
            {
                //_vr.record.Parent.Items.Add(record);
                _vr.AppendBrother(record);
                isNew = false;
            }
            else
            {
                _vr.Update();
            }
        }

        private IPDDatabase CreateNew(string input, string output)
        {
            IPDDatabase record = new IPDAutoText(_vr.record.Parent);
            record.dbId = defDbId;
            record.dbver = defDbVer;

            Random r = new Random((int)DateTime.Now.Ticks);
            record.uid = EncUtil.Number2Bin(r.Next());

            IPDField f1 = new IPDField(record);
            if (EncUtil.IsAsciiOnly(input))
            {
                f1.type = fldtypeAutoTextInput;
                f1.IsUnicode = false;
            }
            else
            {
                f1.type = fldtypeAutoTextInputNonEng;
                f1.IsUnicode = true;
            }
            f1.len = 4;
            record.Items.Add(f1);

            IPDField f2 = new IPDField(record);
            if (EncUtil.IsAsciiOnly(output))
            {
                f2.type = fldtypeAutoTextOutput;
                f2.IsUnicode = false;
            }
            else
            {
                f2.type = fldtypeAutoTextOutputNonEng;
                f2.IsUnicode = true;
            }
            f2.len = 4;
            record.Items.Add(f2);

            if (f1.IsUnicode || f2.IsUnicode)
                record.IsUnicode = true;
            else
                record.IsUnicode = false;

            IPDField f31 = new IPDField(record, fldtypeAutoTextCase1, 4);
            f31.IsUnicode = record.IsUnicode;
            record.Items.Add(f31);

            IPDField f32 = new IPDField(record, fldtypeAutoTextCase2, 4);
            f32.IsUnicode = record.IsUnicode;
            record.Items.Add(f32);

            IPDField f4 = new IPDField(record, fldtypeAutoTextLanguage, 4);
            f4.IsUnicode = record.IsUnicode;
            record.Items.Add(f4);

            return record;
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {

        }
    }
}

